#!/usr/bin/env python
# *-* encoding: utf8
# 
# Copyright (c) 2006 Stian Soiland
# 
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# 
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
# 
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
#
# Author: Stian Soiland <stian@soiland.no>
# URL: http://soiland.no/i/src/
# License: LGPL
#
"""Test file system abstraction.

Tests for fs.py.
"""


import unittest
import shutil
import tempfile
import os
import sha
import time

import fs
import rdffs

from teststore import CreateDirMixin

class FSMixin(object):
    def setUp(self):
        """Create a filesystem instance"""
        self.fs = fs.dummies()
        self.root = self.fs.root

class RDFFSMixin(CreateDirMixin):
    def setUp(self):
        """Create a filesystem instance"""
        super(RDFFSMixin, self).setUp()
        self.fs = rdffs.dummies()
        self.root = self.fs.root
    

class _TestGet(object):

    def testGetDir(self):
        pub = self.root.get("pub")
        self.assertEqual("/pub", pub.path())

        pub = self.root.get("pub/")
        self.assertEqual("/pub", pub.path())

        pub = self.root.get("pub//")
        self.assertEqual("/pub", pub.path())

        pub = self.root.get("/pub//")
        self.assertEqual("/pub", pub.path())

        pub = self.root.get("/pub/.")
        self.assertEqual("/pub", pub.path())

        pub = self.root.get("/pub/./")
        self.assertEqual("/pub", pub.path())

        root = self.root.get("/pub/..")
        self.assertEqual("/", root.path())
        
    def testGetRelative(self):
        passwd = self.root.get("pub/../etc/./../../etc/././passwd/../../pub")
        self.assert_(hasattr(passwd, "size"))
        self.assertEqual(passwd, self.root.get("/etc/passwd"))
        
#class TestGet(FSMixin, _TestGet, unittest.TestCase):
#    pass
    
class TestGetRDF(RDFFSMixin, _TestGet, unittest.TestCase):
    pass

class _TestFileObject(object):

    def testOpenDirectory(self):
        self.assertRaises(IOError, self.fs.open, "/etc")
        
    def testOpenRead(self):
        file = self.fs.open("/pub/hello.txt")
        self.assertEqual("Hello world\n", file.read())
    
    def testOpenWrite(self):
        file = self.fs.open("/pub/hello.txt", "w")
        file.write("Replaced\n")
        file.close()
        other = self.fs.open("/pub/hello.txt")
        self.assertEqual("Replaced\n", other.read())

    def testLastModifiedUpdated(self):
        original_time = self.fs.info("/pub/hello.txt").lastmodified
        file = self.fs.open("/pub/hello.txt", "a")
        file.write("ooo")
        # Becuase we haven't flushed or closed yet
        self.assertEqual(original_time,
            self.fs.info("/pub/hello.txt").lastmodified)
        file.close()
        # We changed it, should be newer
        self.assertTrue(original_time < 
            self.fs.info("/pub/hello.txt").lastmodified)

    def testLastModifiedNotUpdated(self):
        original_time = self.fs.info("/pub/hello.txt").lastmodified
        file = self.fs.open("/pub/hello.txt", "a")
        # Becuase we haven't flushed or closed yet
        self.assertEqual(original_time,
            self.fs.info("/pub/hello.txt").lastmodified)
        file.close()
        # We didn't change it, should be unchanged 
        self.assertEqual(original_time,
            self.fs.info("/pub/hello.txt").lastmodified)
        
    def testOpenAppend(self):
        file = self.fs.open("/pub/hello.txt", "a")
        file.write("Appended\n")
        file.close()
        other = self.fs.open("/pub/hello.txt")
        self.assertEqual("Hello world\nAppended\n", 
                         other.read())
    
    def testCantWrite(self):
        file = self.fs.open("/pub/hello.txt", "r")
        self.assertRaises(IOError, file.write, "Oh noes\n")
        self.assertRaises(IOError, file.writelines, ["Not allowed\n"])
        self.assertRaises(IOError, file.flush)
        self.assertRaises(IOError, file.truncate)
        file.close()
        other = self.fs.open("/pub/hello.txt")
        self.assertEqual("Hello world\n", other.read())
    
    def testCantRead(self):
        file = self.fs.open("/pub/hello.txt", "w")
        file.write("Hello there\n")
        file.seek(0)
        self.assertRaises(IOError, file.read)
        self.assertRaises(IOError, file.readline)
        self.assertRaises(IOError, file.readlines)
        self.assertRaises(IOError, file.next)
        self.assertRaises(IOError, iter, file)
   
    def testCanRead(self):
        file = self.fs.open("/pub/hello.txt", "r")
        hello = "Hello world\n"
        self.assertEqual(hello, file.read())
        self.assertEqual("", file.read())
        file.seek(0)
        self.assertEqual(hello, file.readline())
        file.seek(0)
        self.assertEqual([hello], file.readlines())
        file.seek(0)
        self.assertEqual(hello, iter(file).next())
         
    def testCanReadAndWrite(self):
        file = self.fs.open("/pub/hello.txt", "r+")
        file.write("HELLO")
        self.assertEqual(" world\n", file.read())
        file.seek(0)
        self.assertEqual("HELLO world\n", file.read())
        file.close()
        other = self.fs.open("/pub/hello.txt")
        self.assertEqual("HELLO world\n", other.read())

        
    def testOpenMissing(self):
        self.assertRaises(IOError, self.fs.open, "/etc/notfound.txt") 
            

#class TestFileObject(FSMixin, _TestFileObject, unittest.TestCase):
#    pass

class TestFileObjectRDF(RDFFSMixin, _TestFileObject, unittest.TestCase):
    pass




class _TestFileSystem(object):
    """Test file system utility functions like
    move, copy, mkdir.
    """
    

if __name__ == "__main__":
    unittest.main()

